/*
	iter.h		Iterators
	Copyright (c) 2000, 2001, 2003, 2004 Kriang Lerdsuwanakij
	email:		lerdsuwa@users.sourceforge.net

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef ITER_H
#define ITER_H

#include "board.h"
#include "order.h"

// A linked-list containing empty positions
struct empty_endgame_entry {
	int			pos;
	empty_endgame_entry*	next;
};

// Empty positions information during alpha-beta searching
struct empty_endgame_info {
	int	empty_endgame_size;
	empty_endgame_entry *empty_endgame_head;
	empty_endgame_entry empty_endgame_order[NUM_MOVE];
};

// Initialize empty_endgame_info from current board
void	init_endgame_iterator(byte_board_info *board, empty_endgame_info &info);

// Directions
#define DIR_N	0
#define DIR_NE	1
#define DIR_E	2
#define DIR_SE	3
#define DIR_S	4
#define DIR_SW	5
#define DIR_W	6
#define DIR_NW	7


/*************************************************************************
	Iterate positions from top-left to bottom-right
*************************************************************************/

struct board_iterator {
	int	pos;
	
	void	init_pos(int pos_ = 0)
	{
		pos = pos_;
	}
	
	bool	next()
	{
		pos++;
		if (pos == 64)
			return false;
		return true;
	}
};

/*************************************************************************
	Iterate positions for mid-game searching
*************************************************************************/

/*************************************************************************
	Iterate positions for end-game searching
*************************************************************************/

struct board_full_endgame_iterator {
	int	pos;
	int	pos_real;

	void	init_pos(int pos_ = 0)
	{
		pos_real = pos_;
		pos = endgame_order[pos_real];
	}
	
	bool	next()
	{
		pos_real++;
				// Only NUM_MOVE (60) since we exclude
				// center squares here
		if (pos_real == NUM_MOVE)
			return false;

		pos = endgame_order[pos_real];
		return true;
	}
};

/*************************************************************************
	Iterate positions for end-game searching
*************************************************************************/

struct board_endgame_iterator {
	int	pos;
	empty_endgame_info	&info;
	empty_endgame_entry*	pos_real;
	empty_endgame_entry*	pos_prev;
	typedef	empty_endgame_entry*	save_type;

	board_endgame_iterator(empty_endgame_info &info_) : info(info_)
	{
	}

	void	init_pos()
	{
		pos_real = info.empty_endgame_head;
		pos_prev = 0;
				// Don't check if pos_real == 0 here
		pos = pos_real->pos;
	}
	
	bool	next()
	{
		if (pos_real && pos_real->next) {
			pos_prev = pos_real;
			pos_real = pos_real->next;
			pos = pos_real->pos;
			return true;
		}
		return false;
	}

	void	remove_current()
	{
		if (pos_prev)
			pos_prev->next = pos_real->next;
		else
			info.empty_endgame_head = pos_real->next;
	}

	void	restore_current()
	{
		if (pos_prev)
			pos_prev->next = pos_real;
		else
			info.empty_endgame_head = pos_real;
	}
};

/*************************************************************************
	Iterate positions in any of eight directions
*************************************************************************/

struct board_dir_iterator {
	int	x;
	int	y;
	int	pos;
	
	void	init_xy(int x_ = 0, int y_ = 0)
	{
		x = x_;
		y = y_;
		pos = xy_to_pos(x_, y_);
	}
	
	void	init_pos(int pos_ = 0)
	{
		x = pos_to_x(pos_);
		y = pos_to_y(pos_);
		pos = pos_;
	}
	
	bool	next_N()
	{
		if (y == 0)
			return false;
		y--;
		pos -= 8;
		return true;
	}

	bool	next_NE()
	{
		if (x == 7 || y == 0)
			return false;
		x++;
		y--;
		pos -= 7;
		return true;
	}

	bool	next_E()
	{
		if (x == 7)
			return false;
		x++;
		pos++;
		return true;
	}

	bool	next_SE()
	{
		if (x == 7 || y == 7)
			return false;
		x++;
		y++;
		pos += 9;
		return true;
	}

	bool	next_S()
	{
		if (y == 7)
			return false;
		y++;
		pos += 8;
		return true;
	}

	bool	next_SW()
	{
		if (x == 0 || y == 7)
			return false;
		x--;
		y++;
		pos += 7;
		return true;
	}

	bool	next_W()
	{
		if (x == 0)
			return false;
		x--;
		pos--;
		return true;
	}

	bool	next_NW()
	{
		if (x == 0 || y == 0)
			return false;
		y--;
		x--;
		pos -= 9;
		return true;
	}

	bool	next_dir(int dir)
	{
		switch (dir) {
			case DIR_N:
				return next_N();
			case DIR_NE:
				return next_NE();
			case DIR_E:
				return next_E();
			case DIR_SE:
				return next_SE();
			case DIR_S:
				return next_S();
			case DIR_SW:
				return next_SW();
			case DIR_W:
				return next_W();
			case DIR_NW:
				return next_NW();
			default:
				return false;
		}
	}

	void	next_N_nocheck()
	{
		y--;
		pos -= 8;
	}

	void	next_NE_nocheck()
	{
		x++;
		y--;
		pos -= 7;
	}

	void	next_E_nocheck()
	{
		x++;
		pos++;
	}

	void	next_SE_nocheck()
	{
		x++;
		y++;
		pos += 9;
	}

	void	next_S_nocheck()
	{
		y++;
		pos += 8;
	}

	void	next_SW_nocheck()
	{
		x--;
		y++;
		pos += 7;
	}

	void	next_W_nocheck()
	{
		x--;
		pos--;
	}

	void	next_NW_nocheck()
	{
		y--;
		x--;
		pos -= 9;
	}

	void	next_dir_nocheck(int dir)
	{
		switch (dir) {
			case DIR_N:
				next_N_nocheck();
				return;
			case DIR_NE:
				next_NE_nocheck();
				return;
			case DIR_E:
				next_E_nocheck();
				return;
			case DIR_SE:
				next_SE_nocheck();
				return;
			case DIR_S:
				next_S_nocheck();
				return;
			case DIR_SW:
				next_SW_nocheck();
				return;
			case DIR_W:
				next_W_nocheck();
				return;
			case DIR_NW:
				next_NW_nocheck();
				return;
		}
	}
};

#endif /* ITER_H */
